function [mergedPoses] = interpolate(poseVec1, poseVec2, alphas)
	pose1(2:15, :) = reshape(poseVec1, [3 14])';
	pose2(2:15, :) = reshape(poseVec2, [3 14])';
	idx = num2cell(2:15);
	Pelvis = 1;
	[Thorax, LeftShoulder, LeftElbow, LeftWrist, ...
		RightShoulder, RightElbow, RightWrist, ...
		LeftHip, LeftKnee, LeftAnkle, ...
		RightHip, RightKnee, RightAnkle, Head] = idx{:};

	hierarchy = ...
		{Pelvis, {
			{LeftHip, {
				{LeftKnee, {
					{LeftAnkle, 0}}}}}, 
			{RightHip, {
				{RightKnee, {
					{RightAnkle, 0}}}}}, 
			{Thorax, {
				{LeftShoulder, {
					{LeftElbow, {
						{LeftWrist, 0}}}}}, 
				{RightShoulder, {
					{RightElbow, {
						{RightWrist, 0}}}}},  
				{Head, 0}}}}};


	function poseRel = abs2rel(poseAbs)
	% converts absolute coordinates to relative
		poseRel = zeros(15, 3);

		function parentCoord = modifyPose(nodeId, parentCoord)
			poseRel(nodeId, :) = poseAbs(nodeId, :) - parentCoord;
			parentCoord = poseAbs(nodeId, :);
		end

		treeMap(@modifyPose, [0 0 0], hierarchy);
	end

	pose1 = abs2rel(pose1);
	pose2 = abs2rel(pose2);

	function [] = transform(tree, trans1, trans2, alpha)
	% blends two poses recursively
		current = tree{1};
		mergedPose(current, :) = trans1(1:3, 4)';

		if ~iscell(tree{2})
			% leaf
			assert(tree{2} == 0);
			return;
		end

		for child = tree{2}'
			child = child{:};
			nodeId = child{1};

			ori1 = trans1(1:3, 4);
			coord1 = trans1 * [pose1(nodeId, :) 1]';
			coord1 = coord1(1:3) - ori1;

			ori2 = trans2(1:3, 4);
			coord2 = trans2 * [pose2(nodeId, :) 1]';
			coord2 = coord2(1:3) - ori2;

			normal = cross(coord1, coord2);
			normLen = norm(normal);

			if all(abs(normal) < eps)  % almost parallel
				rot1 = eye(4);
				rot2 = rot1;
			else
				diffAngle = atan2(normLen, dot(coord1, coord2));
				rotAngle1 = diffAngle * alpha;
				rotAngle2 = diffAngle * (alpha - 1);
				normal = normal / normLen;
				rot1 = makehgtform('axisrotate', normal, rotAngle1);
				rot2 = makehgtform('axisrotate', normal, rotAngle2);
			end

			offsets = [rot1 * [coord1; 1], rot2 * [coord2; 1]] * ...
				[alpha - 1, alpha; 1 - alpha, -alpha];

			offset1 = offsets(1:3, 1);
			extend1 = makehgtform('translate', offset1);
			transNew1 = makehgtform('translate', ori1) * ...
				extend1 * rot1 * makehgtform('translate', -ori1) * ...
					trans1 * makehgtform('translate', pose1(nodeId, :)');

			offset2 = offsets(1:3, 2);
			extend2 = makehgtform('translate', offset2);
			transNew2 = makehgtform('translate', ori2) * ...
				extend2 * rot2 * makehgtform('translate', -ori2) * ...
					trans2 * makehgtform('translate', pose2(nodeId, :)');

			assert(sum(abs(transNew1(1:3, 4) - transNew2(1:3, 4))) < 1e-6);

			transform(child, transNew1, transNew2, alpha);
		end
	end

	mergedPoses = zeros(length(alphas), 42);
	for i = 1:length(alphas)
		mergedPose = zeros(15, 3);
		transform(hierarchy, eye(4), eye(4), alphas(i));
		mergedPose = mergedPose(2:15, :)';
		mergedPoses(i, :) = mergedPose(:);
	end
end

function [] = treeMap(f, param, tree)
	parent = tree{1};
	param = f(parent, param);
	if iscell(tree{2})
		for child = tree{2}'
			child = child{:};
			treeMap(f, param, child);
		end
	else
		% leaf
		assert(tree{2} == 0);
	end
end
